1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.annotations.VisibleForTesting;
21  import com.google.common.base.Preconditions;
22  
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.Set;
26  
27  /**
28   * Implementation of {@link Multimap} using hash tables.
29   *
30   * <p>The multimap does not store duplicate key-value pairs. Adding a new
31   * key-value pair equal to an existing key-value pair has no effect.
32   *
33   * <p>Keys and values may be null. All optional multimap methods are supported,
34   * and all returned views are modifiable.
35   *
36   * <p>This class is not threadsafe when any concurrent operations update the
37   * multimap. Concurrent read operations will work correctly. To allow concurrent
38   * update operations, wrap your multimap with a call to {@link
39   * Multimaps#synchronizedSetMultimap}.
40   *
41   * @author Jared Levy
42   * @since 2.0 (imported from Google Collections Library)
43   */
44  @GwtCompatible(serializable = true, emulated = true)
45  public final class HashMultimap<K, V> extends AbstractSetMultimap<K, V> {
46    private static final int DEFAULT_VALUES_PER_KEY = 2;
47  
48    @VisibleForTesting
49    transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
50  
51    /**
52     * Creates a new, empty {@code HashMultimap} with the default initial
53     * capacities.
54     */
55    public static <K, V> HashMultimap<K, V> create() {
56      return new HashMultimap<K, V>();
57    }
58  
59    /**
60     * Constructs an empty {@code HashMultimap} with enough capacity to hold the
61     * specified numbers of keys and values without rehashing.
62     *
63     * @param expectedKeys the expected number of distinct keys
64     * @param expectedValuesPerKey the expected average number of values per key
65     * @throws IllegalArgumentException if {@code expectedKeys} or {@code
66     *      expectedValuesPerKey} is negative
67     */
68    public static <K, V> HashMultimap<K, V> create(
69        int expectedKeys, int expectedValuesPerKey) {
70      return new HashMultimap<K, V>(expectedKeys, expectedValuesPerKey);
71    }
72  
73    /**
74     * Constructs a {@code HashMultimap} with the same mappings as the specified
75     * multimap. If a key-value mapping appears multiple times in the input
76     * multimap, it only appears once in the constructed multimap.
77     *
78     * @param multimap the multimap whose contents are copied to this multimap
79     */
80    public static <K, V> HashMultimap<K, V> create(
81        Multimap<? extends K, ? extends V> multimap) {
82      return new HashMultimap<K, V>(multimap);
83    }
84  
85    private HashMultimap() {
86      super(new HashMap<K, Collection<V>>());
87    }
88  
89    private HashMultimap(int expectedKeys, int expectedValuesPerKey) {
90      super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys));
91      Preconditions.checkArgument(expectedValuesPerKey >= 0);
92      this.expectedValuesPerKey = expectedValuesPerKey;
93    }
94  
95    private HashMultimap(Multimap<? extends K, ? extends V> multimap) {
96      super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(
97          multimap.keySet().size()));
98      putAll(multimap);
99    }
100 
101   /**
102    * {@inheritDoc}
103    *
104    * <p>Creates an empty {@code HashSet} for a collection of values for one key.
105    *
106    * @return a new {@code HashSet} containing a collection of values for one key
107    */
108   @Override Set<V> createCollection() {
109     return Sets.<V>newHashSetWithExpectedSize(expectedValuesPerKey);
110   }
111 }
112